{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d3dbe1d4-b3e4-4330-8b7a-7cb00aec661a",
   "metadata": {},
   "source": [
    "## 1. Figure 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fca21f0e-92fd-4415-b0f7-6c10b48e8504",
   "metadata": {},
   "outputs": [],
   "source": [
    "import folium\n",
    "from folium.features import DivIcon\n",
    "from branca.element import Template, MacroElement\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 1) Data (from user)\n",
    "# ------------------------------------------------------------\n",
    "# NOTE:\n",
    "# - Saeul NPP is in Ulju-gun, Ulsan (NOT Busan).\n",
    "# - Coordinates below are approximate site centroids for visualization.\n",
    "#   Replace lat/lon with official coordinates if you prefer.\n",
    "\n",
    "sites = [\n",
    "    {\"site\": \"Hanbit NPP\",  \"admin\": \"Yeonggwang-gun, Jeollanam-do\", \"lat\": 35.2741666666666, \"lon\": 126.514086111111, \"total\": 6, \"maint\": 2},\n",
    "    {\"site\": \"Hanul NPP\",   \"admin\": \"Uljin-gun, Gyeongsangbuk-do\",  \"lat\": 36.9901861111111, \"lon\": 129.402786111111, \"total\": 7, \"maint\": 1},\n",
    "    {\"site\": \"Wolsong NPP\", \"admin\": \"Gyeongju-si, Gyeongsangbuk-do\",\"lat\": 35.8531694444444, \"lon\": 129.227022222222, \"total\": 5, \"maint\": 0},\n",
    "    {\"site\": \"Saeul NPP\",   \"admin\": \"Ulju-gun, Ulsan\",             \"lat\": 35.5223064790022, \"lon\": 129.242474811581, \"total\": 2, \"maint\": 0},\n",
    "    {\"site\": \"Kori NPP\",    \"admin\": \"Gijang-gun, Busan\",           \"lat\": 35.2447754075554, \"lon\": 129.222287283017, \"total\": 5, \"maint\": 1},\n",
    "]\n",
    "\n",
    "for s in sites:\n",
    "    s[\"operating\"] = s[\"total\"] - s[\"maint\"]\n",
    "    s[\"maint_rate\"] = s[\"maint\"] / s[\"total\"] if s[\"total\"] else 0.0\n",
    "\n",
    "# Optional interpretive contrast: Seoul has 0 nuclear reactors\n",
    "seoul = {\"name\": \"Seoul (Capital Region)\", \"lat\": 37.5665, \"lon\": 126.9780}\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 2) Helper: color by maintenance share\n",
    "# ------------------------------------------------------------\n",
    "def color_by_maint_rate(r: float) -> str:\n",
    "    \"\"\"\n",
    "    0%    -> green\n",
    "    <=20% -> yellow\n",
    "    >20%  -> red\n",
    "    \"\"\"\n",
    "    if r == 0:\n",
    "        return \"#2ca25f\"\n",
    "    elif r <= 0.2:\n",
    "        return \"#ffcc00\"\n",
    "    else:\n",
    "        return \"#de2d26\"\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 3) Create map\n",
    "# ------------------------------------------------------------\n",
    "m = folium.Map(\n",
    "    location=[36.3, 127.8],      # roughly Korea center\n",
    "    zoom_start=7,\n",
    "    tiles=\"CartoDB positron\",\n",
    "    control_scale=True\n",
    ")\n",
    "\n",
    "# Feature layers\n",
    "fg_buffers = folium.FeatureGroup(name=\"Buffers (10 km / 30 km)\", show=True).add_to(m)\n",
    "fg_circles = folium.FeatureGroup(name=\"Circles: size=total units, color=maintenance share\", show=True).add_to(m)\n",
    "fg_labels  = folium.FeatureGroup(name=\"Labels (Operating / Maintenance / Total)\", show=True).add_to(m)\n",
    "fg_markers = folium.FeatureGroup(name=\"Click markers (detailed popup)\", show=False).add_to(m)\n",
    "\n",
    "# Add Seoul marker (0 reactors) for contrast\n",
    "folium.CircleMarker(\n",
    "    location=[seoul[\"lat\"], seoul[\"lon\"]],\n",
    "    radius=6,\n",
    "    weight=2,\n",
    "    color=\"#444\",\n",
    "    fill=True,\n",
    "    fill_opacity=0.15,\n",
    "    tooltip=\"Seoul (0 nuclear reactors)\",\n",
    "    popup=folium.Popup(\"<b>Seoul (Capital Region)</b><br>Number of nuclear reactor units: 0\", max_width=320),\n",
    ").add_to(m)\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 4) Add sites (buffers + circles + labels + markers)\n",
    "# ------------------------------------------------------------\n",
    "for s in sites:\n",
    "    col = color_by_maint_rate(s[\"maint_rate\"])\n",
    "\n",
    "    # --- NEW: subtle buffer circles (10km / 30km) ---\n",
    "    folium.Circle(\n",
    "        location=[s[\"lat\"], s[\"lon\"]],\n",
    "        radius=10_000,           # meters\n",
    "        color=\"#444\",\n",
    "        weight=1,\n",
    "        fill=False,\n",
    "        opacity=0.35,            # subtle\n",
    "        tooltip=f\"{s['site']} – 10 km buffer\",\n",
    "    ).add_to(fg_buffers)\n",
    "\n",
    "    folium.Circle(\n",
    "    location=[s[\"lat\"], s[\"lon\"]],\n",
    "    radius=30_000,           # meters\n",
    "    color=\"#444\",         # slightly darker grey\n",
    "    weight=1,                # keep thin\n",
    "    fill=False,\n",
    "    opacity=0.45,            # ↑ visibility (was ~0.22)\n",
    "    dash_array=\"6,6\",        # clearer dashed pattern\n",
    "    tooltip=f\"{s['site']} – 30 km buffer\",\n",
    "    ).add_to(fg_buffers)\n",
    "\n",
    "    # CircleMarker radius proportional to total units (pixels)\n",
    "    radius = 8 + s[\"total\"] * 4\n",
    "\n",
    "    popup_html = f\"\"\"\n",
    "    <div style=\"font-size: 13px;\">\n",
    "      <b>{s['site']}</b><br>\n",
    "      <span>{s['admin']}</span><br><br>\n",
    "      Total units: <b>{s['total']}</b><br>\n",
    "      Operating: <b>{s['operating']}</b><br>\n",
    "      Under maintenance: <b>{s['maint']}</b><br>\n",
    "      Maintenance share: <b>{s['maint_rate']:.0%}</b>\n",
    "      <hr style=\"margin:6px 0;\">\n",
    "      <i>Encoding</i><br>\n",
    "      • Circle size = total units<br>\n",
    "      • Circle color = maintenance share (0% green / ≤20% yellow / >20% red)<br>\n",
    "      • Rings = 10 km (solid) / 30 km (dashed)\n",
    "    </div>\n",
    "    \"\"\"\n",
    "\n",
    "    # Main circle\n",
    "    folium.CircleMarker(\n",
    "        location=[s[\"lat\"], s[\"lon\"]],\n",
    "        radius=radius,\n",
    "        weight=2,\n",
    "        color=col,\n",
    "        fill=True,\n",
    "        fill_color=col,\n",
    "        fill_opacity=0.35,\n",
    "        tooltip=f\"{s['site']} | {s['admin']} | Total {s['total']} (Operating {s['operating']}, Maint {s['maint']})\",\n",
    "        popup=folium.Popup(popup_html, max_width=420),\n",
    "    ).add_to(fg_circles)\n",
    "\n",
    "    # Optional click marker (precise click target)\n",
    "    folium.Marker(\n",
    "        location=[s[\"lat\"], s[\"lon\"]],\n",
    "        tooltip=s[\"site\"],\n",
    "        popup=folium.Popup(popup_html, max_width=420),\n",
    "        icon=folium.Icon(color=\"blue\", icon=\"info-sign\"),\n",
    "    ).add_to(fg_markers)\n",
    "\n",
    "    # Label\n",
    "    label = (\n",
    "        f\"{s['site']}\\n\"\n",
    "        f\"{s['admin']}\\n\"\n",
    "        f\"Operating {s['operating']} / Maintenance {s['maint']} (Total {s['total']})\"\n",
    "    )\n",
    "    folium.map.Marker(\n",
    "        [s[\"lat\"], s[\"lon\"]],\n",
    "        icon=DivIcon(\n",
    "            icon_size=(290, 64),\n",
    "            icon_anchor=(0, -10),\n",
    "            html=f\"\"\"\n",
    "            <div style=\"\n",
    "                font-size:12px;\n",
    "                font-weight:600;\n",
    "                color:#111;\n",
    "                text-shadow: 0 0 3px rgba(255,255,255,0.9);\n",
    "                white-space: pre-line;\n",
    "            \">{label}</div>\n",
    "            \"\"\",\n",
    "        ),\n",
    "    ).add_to(fg_labels)\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 5) Legend (moved upward slightly)\n",
    "# ------------------------------------------------------------\n",
    "legend_html = \"\"\"\n",
    "{% macro html(this, kwargs) %}\n",
    "<div style=\"\n",
    "position: fixed;\n",
    "bottom: 60px;        /* moved upward slightly */\n",
    "left: 40px;\n",
    "z-index: 9999;\n",
    "background: rgba(255,255,255,0.95);\n",
    "padding: 10px 12px;\n",
    "border: 1px solid #bbb;\n",
    "border-radius: 8px;\n",
    "box-shadow: 0 2px 10px rgba(0,0,0,0.08);\n",
    "font-size: 14px;\n",
    "width: 340px;\n",
    "\">\n",
    "  <div style=\"font-size: 13px; font-weight: 700; margin-bottom: 6px;\">\n",
    "    South Korea Nuclear Power Plant Sites (Summary)\n",
    "  </div>\n",
    "  <div style=\"margin-bottom: 6px;\">\n",
    "    <b>Circle size</b>: Total reactor units\n",
    "  </div>\n",
    "  <div style=\"margin-bottom: 6px;\">\n",
    "    <b>Circle color</b>: Maintenance share\n",
    "  </div>\n",
    "  <div style=\"margin-bottom: 6px;\">\n",
    "    <b>Rings</b>: 10 km (solid) and 30 km (dashed) buffers\n",
    "  </div>\n",
    "\n",
    "  <div style=\"display:flex; align-items:center; gap:8px; margin-bottom:4px;\">\n",
    "    <span style=\"display:inline-block;width:12px;height:12px;background:#2ca25f;border:1px solid #2ca25f;border-radius:50%;\"></span>\n",
    "    <span>0% (no units under maintenance)</span>\n",
    "  </div>\n",
    "  <div style=\"display:flex; align-items:center; gap:8px; margin-bottom:4px;\">\n",
    "    <span style=\"display:inline-block;width:12px;height:12px;background:#ffcc00;border:1px solid #ffcc00;border-radius:50%;\"></span>\n",
    "    <span>≤ 20%</span>\n",
    "  </div>\n",
    "  <div style=\"display:flex; align-items:center; gap:8px; margin-bottom:8px;\">\n",
    "    <span style=\"display:inline-block;width:12px;height:12px;background:#de2d26;border:1px solid #de2d26;border-radius:50%;\"></span>\n",
    "    <span>> 20%</span>\n",
    "  </div>\n",
    "\n",
    "  <div style=\"font-size:11px;color:#444;\">\n",
    "  </div>\n",
    "</div>\n",
    "{% endmacro %}\n",
    "\"\"\"\n",
    "macro = MacroElement()\n",
    "macro._template = Template(legend_html)\n",
    "m.get_root().add_child(macro)\n",
    "\n",
    "# Layer control\n",
    "folium.LayerControl(collapsed=False).add_to(m)\n",
    "\n",
    "# ------------------------------------------------------------\n",
    "# 6) Save\n",
    "# ------------------------------------------------------------\n",
    "output_html = \"korea_npp_sites_map_english_buffers.html\"\n",
    "m.save(output_html)\n",
    "print(f\"Saved: {output_html}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22a2cd2f-e09f-4be6-8687-0bba01782b41",
   "metadata": {},
   "source": [
    "## 2.Figure 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c91fe7ff-0051-4258-aad8-ca1303721e79",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import geopandas as gpd\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from matplotlib.ticker import FuncFormatter\n",
    "from shapely.ops import unary_union\n",
    "import matplotlib as mpl\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "993a8360-b3cb-4d45-b38c-ba9b05a7fff8",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_excel(r\"E:\\df_energy_consum.xlsx\")\n",
    "gdf_base = gpd.read_file(r\"E:\\SIDO_MAP_2022.json\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39d05639-a394-4971-8312-c42e74df2b73",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Merge\n",
    "gdf = gdf_base.merge(df, left_on=\"CTP_KOR_NM\", right_on=\"si-do\", how=\"left\")\n",
    "\n",
    "# ----------------------------\n",
    "# 2) Variables and display names (add unit)\n",
    "# ----------------------------\n",
    "map_vars = [\n",
    "    (\"Residential\", \"2025 Residential (MWh)\"),\n",
    "    (\"Commercial\",  \"2025 Commercial (MWh)\"),\n",
    "    (\"Industrial\",  \"2025 Industrial (MWh)\"),\n",
    "    (\"Total\",       \"2025 Total (MWh)\")\n",
    "]\n",
    "\n",
    "# Formatter for full numbers (no scientific notation)\n",
    "fmt_full = FuncFormatter(lambda x, pos: f\"{x:,.0f}\")\n",
    "\n",
    "# ----------------------------\n",
    "# 3) Plot setup (tight maps)\n",
    "# ----------------------------\n",
    "fig, axs = plt.subplots(2, 2, figsize=(16, 12))\n",
    "axs = axs.flatten()\n",
    "\n",
    "for i, (var, title) in enumerate(map_vars):\n",
    "    ax = axs[i]\n",
    "\n",
    "    gdf.plot(\n",
    "        column=var,\n",
    "        cmap=\"YlGnBu\",\n",
    "        linewidth=0.3,\n",
    "        edgecolor=\"black\",\n",
    "        ax=ax,\n",
    "        legend=True,\n",
    "        legend_kwds={\n",
    "            \"shrink\": 0.70,\n",
    "            \"label\": \"\"  # unit shown here\n",
    "        }\n",
    "    )\n",
    "\n",
    "    ax.set_title(title, fontsize=25, pad=10)\n",
    "    ax.axis(\"off\")\n",
    "\n",
    "    # --- Get the colorbar axis created for THIS subplot ---\n",
    "    # GeoPandas appends a new colorbar axis at the end each time legend=True\n",
    "    cbar_ax = ax.get_figure().axes[-1]\n",
    "\n",
    "    # Full numbers + readable fontsize\n",
    "    cbar_ax.yaxis.set_major_formatter(fmt_full)\n",
    "    cbar_ax.tick_params(labelsize=18)\n",
    "\n",
    "    # Also make the colorbar label readable\n",
    "    cbar_ax.set_ylabel(\"\", fontsize=18)\n",
    "\n",
    "# ----------------------------\n",
    "# 4) Make spacing tighter than tight_layout()\n",
    "# ----------------------------\n",
    "# Use subplots_adjust to control inter-panel gaps tightly\n",
    "fig.subplots_adjust(\n",
    "    left=0.01, right=0.99,\n",
    "    bottom=0.02, top=0.94,\n",
    "    wspace=0,   # 🔴 핵심: 0.1 → 0.02\n",
    "    hspace=0.05\n",
    ")\n",
    "\n",
    "# Save\n",
    "out_path = r\"E:\\불평등 연구\\데이터\\67_원자력_지역불평등_미디어\\figures\\figure_3.png\"\n",
    "plt.savefig(out_path, dpi=600, bbox_inches=\"tight\")\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
